package Fp

import (
	"fmt"
	"db2s/full"
	"db2s/parDef"
	"regexp"
	"strings"
	"sync/atomic"
)

func (sp TaskDistribution) firstSendMsg(s parDef.IndexPart) {
	sp.First.Result <- s
}
func (sp TaskDistribution) firstCloseMsg() {
	if sp.First.Result != nil {
		close(sp.First.Result)
	}
}
func (sp TaskDistribution) firstGetLeftDirection() []map[string]string {
	return getLeftDirection(sp.First.Batch.WhereGenerate.LeftDirection)
}
func (sp TaskDistribution) firstGetRightDirection() []map[string]string {
	return getRightDirection(sp.First.Batch.WhereGenerate.RightDirection)
}
func (sp TaskDistribution) getFirstSemLogSeq() int64 {
	if sp.First.FirstSemLogSeq == nil {
		return 0
	}
	return atomic.LoadInt64(sp.First.FirstSemLogSeq)
}

func (sp TaskDistribution) firstGetWcValue() []string {
	return getWcValue(sp.First.WC)
}
func (sp TaskDistribution) firstGetWsValue() []string {
	return getWsValue(sp.First.WS)
}
func (sp TaskDistribution) firstGetSwsMd5() string {
	return fmt.Sprintf("%v", getAtomicValue(sp.First.SwsMd5))
}
func getTypeValue(Type *atomic.Value) (res []string) {
	if Type == nil {
		return
	}
	val := getAtomicValue(Type)
	if val == nil {
		return []string{}
	}
	return val.([]string)
}
func getNullValue(null *atomic.Value) (res []string) {
	if null == nil {
		return
	}
	val := getAtomicValue(null)
	if val == nil {
		return
	}
	return val.([]string)
}
func (sp TaskDistribution) firstErrClose(logSeq1, logSeq2 int64) bool {
	var (
		event = "[firstErrClose]"
	)
	if sp.ErrEnd != nil {
		if val := atomic.LoadInt64(sp.ErrEnd); val < 0 {
			errorActive(fmt.Sprintf("(%d-%v) %v setupEnd&: setupEnd&: Received an error of table %v.%v(%v).", logSeq1, logSeq2, event, sp.TableObject.Schema, sp.TableObject.Table, sp.TableObject.PartitionName))
			sp.firstSendMsg(parDef.IndexPart{Error: fmt.Sprintf("%v", getAtomicValue(sp.First.ErrorStr))})
			return true
		}
	}
	return false
}

func getIndexColTypeMap(ss parDef.Object, column string) (res parDef.ColMetaMapS) {
	for _, col := range ss.Column {
		if strings.EqualFold(col.ColumnName, column) {
			return col
		}
	}
	return
}

/*
FirstColumnType 获取索引的数据类型
*/
func (sp TaskDistribution) FirstColumnType() bool {
	var event = "[columnType]"
	swapAtomicValue(sp.First.Type, func() (res []string) {
		for _, v := range sp.SrcParameter.Object.IndexCol {
			res = append(res, getIndexColTypeMap(sp.SrcParameter.Object, v).TypeBelong)
		}
		return
	}())
	swapAtomicValue(sp.First.Null, func() (res []string) {
		for _, v := range sp.SrcParameter.Object.IndexCol {
			res = append(res, getIndexColTypeMap(sp.SrcParameter.Object, v).ColNullMap)
		}
		return
	}())
	infoActive(fmt.Sprintf("(%v) %v Get the index column data type of table %v.%v. index column is {%v} column dataType is {%v}", sp.LogSeq, event, sp.TableObject.Schema, sp.TableObject.Table, sp.getFirstNameStringSlice(), getTypeValue(sp.First.Type)))
	return true
}

func (sp TaskDistribution) columnValue(cds, wc, ws []string) (compareResult []int, err error) {
	//for k := range sp.TableInfo.IndexColumn {
	//	var r int
	//	if r, err = ValueCompare(cds[k], wc[k], ws[k]); err != nil {
	//		return
	//	}
	//	compareResult = append(compareResult, r)
	//}
	return
}
func newColumnValue(full full.Full, cdn, cds, wc, ws []string) (compareResult []int, err error) {
	for k := range cdn {
		var r int
		var val = []string{wc[k], ws[k]}
		var col = []string{cdn[k], cds[k]}
		if r, err = ValueCompare(full, col, val); err != nil {
			return
		}

		compareResult = append(compareResult, r)
	}
	return
}
func (sp TaskDistribution) firstQueryConditionsLeftIndentation() {
	var newLeftDirection, newRightDirection []map[string]string
	for k, v := range sp.firstGetLeftDirection()[:len(sp.firstGetLeftDirection())-1] {
		if k == len(sp.firstGetLeftDirection())-2 && (strings.EqualFold(v["querySymbolLeft"], ">=") || strings.EqualFold(v["querySymbolLeft"], "=")) {
			v["querySymbolLeft"] = ">"
			newLeftDirection = append(newLeftDirection, v)
			break
		} else {
			newLeftDirection = append(newLeftDirection, v)
		}
	}
	if len(sp.getFirstNameStringSlice()) > 1 {
		swapAtomicValue(sp.First.Name, sp.getFirstNameStringSlice()[:len(sp.getFirstNameStringSlice())-1])
	}
	swapAtomicValue(sp.First.Batch.WhereGenerate.LeftDirection, newLeftDirection)
	swapAtomicValue(sp.First.Batch.WhereGenerate.RightDirection, newRightDirection)
	swapAtomicValue(sp.First.WS, []string{})
	swapAtomicValue(sp.First.WC, []string{})
	//sps.infoActive(fmt.Sprintf(fmt.Sprintf("(%d-%v) %v setup5&: index chunk segment [not value] result of table:%v.%v(%v) index Column:%v index Column dataType:%v. [ls=0] ls:%v,first contitions:ws:%v wc %v sws: left %v right %v", logSeq, sps.getFirstSemLogSeq(), event, sps.TableObject.Schema, sps.TableObject.Table, sps.TableObject.PartitionName, cn1, cds, s.Limit.Pagination, ws, wc, s.WhereGenerate.LeftDirection, s.WhereGenerate.RightDirection)))
}
func (sp TaskDistribution) firstIndentation() int64 {
	switch {
	case len(sp.getFirstNameStringSlice()) <= 1, len(sp.firstGetLeftDirection()) <= 1, len(sp.firstGetLeftDirection()) > len(sp.getFirstNameStringSlice()):
		return 2 //退出
	case len(sp.getFirstNameStringSlice()) > 1 && len(sp.firstGetLeftDirection()) <= len(sp.getFirstNameStringSlice()):
		sp.firstQueryConditionsLeftIndentation()
		return 1 //正常执行
	default:
		return 0 //正常执行
	}
}
func (sp TaskDistribution) firstNotSegmentationValue() int64 {
	pagination := sp.First.Batch.Limit.Pagination
	switch len(sp.firstGetWcValue()) {
	case 0:
		switch atomic.LoadInt64(pagination) {
		case 0:
			atomic.SwapInt32(sp.First.Batch.Limit.ModifyS, 0)
			return sp.firstIndentation()
		case 1:
			swapLimitPagination(pagination, 0)
		default:
			atomic.SwapInt32(sp.First.Batch.Limit.ModifyS, 1)
			swapLimitPagination(pagination, atomic.LoadInt64(pagination)/2)
		}
		return 1 //跳过
	default:
		return 0
	}
}

// ParseWhereClause 解析WHERE条件
func ParseWhereClause(whereClause string) []map[string]string {
	// 更新正则表达式以支持 IS NULL 和 IS NOT NULL
	re := regexp.MustCompile(`(?i)(\w+)\s*(=|<>|!=|>=|<=|>|<|IS)\s*(NULL|NOT NULL|('[^']*'|\d+))?`)
	// 使用 AND 分割条件
	andParts := strings.Split(whereClause, " AND ")
	var conditions []map[string]string
	for _, orPart := range andParts {
		orPart = strings.TrimSpace(orPart)
		matches := re.FindAllStringSubmatch(orPart, -1)
		if len(matches) > 0 {
			conditionMap := make(map[string]string)
			for _, match := range matches {
				if len(match) > 2 {
					field := strings.TrimSpace(match[1])
					operator := strings.TrimSpace(match[2])
					value := ""
					if len(match) > 3 && match[3] != "" {
						value = strings.TrimSpace(match[3])
					}
					conditionMap["columnName"] = field
					conditionMap["symbol"] = operator
					conditionMap["conditions"] = value
				}
			}
			conditions = append(conditions, conditionMap)
		}
	}
	return conditions
}
func GetSingleWhereConditions(where map[string]string) (column, symbol, conditions string) {
	var ok1, ok2, ok3 bool
	column, ok1 = where["columnName"]
	symbol, ok2 = where["symbol"]
	conditions, ok3 = where["conditions"]
	if ok1 && ok2 && ok3 {
		return
	}
	return
}
func (sp *TaskDistribution) firstRunInit() bool {
	var (
		event                      = "[event]"
		firstSemLogSeq             int64
		loopFrequency              int64
		wc, ws                     atomic.Value
		name, Type, null           atomic.Value
		breakMd5, swsMd5, errorStr atomic.Value
	)
	debugActive(fmt.Sprintf("(%d) %v setup1&: Start the first level parallel query segmentation of table %v.%v(%v).", sp.LogSeq, event, sp.TableObject.Schema, sp.TableObject.Table, sp.TableObject.PartitionName))
	sp.SrcParameter = sp.Parameter[0]
	sp.First.Type = &Type
	sp.First.Null = &null
	sp.First.Name = &name
	sp.First.SwsMd5 = &swsMd5
	sp.First.BreakMd5 = &breakMd5
	sp.First.ErrorStr = &errorStr
	sp.Object.Column = sp.SrcParameter.Object.Column
	sp.First.Name.Store(sp.SrcParameter.Object.IndexCol)
	if !sp.FirstColumnType() {
		return false
	}
	sp.First.Batch = sp.pInputInit()
	sp.First.WC = &wc
	sp.First.WS = &ws
	sp.First.FirstSemLogSeq = &firstSemLogSeq
	sp.First.LoopFrequency = &loopFrequency
	sp.prefixNullInit()
	if r := ParseWhereClause(sp.StaticP.QueryFilter); len(r) == 1 {
		_, sym, conditions := GetSingleWhereConditions(r[0])
		if strings.EqualFold(sym, "is") && strings.EqualFold(conditions, "null") {
			return false
		}
	}
	return true
}
